#!/bin/bash
if [[ $4 == "" ]]; then
echo " "
echo " Femto OS v 0.92 - Copyright (C) 2008  Ruud Vlaming "
echo " "
echo " This file is part of the Femto OS distribution. "
echo " "
echo " This program is free software: you can redistribute it and/or modify "
echo " it under the terms of the GNU General Public License as published by "
echo " the Free Software Foundation, version 3 of the License. "
echo " "
echo " This program is distributed in the hope that it will be useful, "
echo " but WITHOUT ANY WARRANTY; without even the implied warranty of "
echo " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the "
echo " GNU General Public License for more details. "
echo " "
echo " You should have received a copy of the GNU General Public License "
echo " along with this program.  If not, see <http://www.gnu.org/licenses/>. "
echo " "
echo " Please note that, due to the GPLv3 license, for application of this "
echo " work and/or combined work in embedded systems special obligations apply. "
echo " If these are not to you liking, please know the Femto OS is dual "
echo " licensed. A commercial license and support are available. "
echo " See http://www.femtoos.org/ for details. "
echo " "
echo " "
echo " In the first please find an analysis or you assembly code which is assumed to "
echo " be avr code. A changed register is a register that is only used within"
echo " interruptable sections. Note that this script cannot be 100% failsafe,"
echo " since it is a liniear analysis of the code and cannot follow the program "
echo " sequence through loops. Please check. Use of register r1 is ignored in the"
echo " registeruse table, since it is usually only a read operation. The indicated"
echo " use of the stack is solely the number of push operation within the functions"
echo " and the function calls (pushing pc), please add the size of the context"
echo " (one byte per register) and the minimum required at context save (usually 4"
echo " bytes) to calculate the stackspace needed. "
echo " "
echo " Column 1:   name of function "
echo " Column 2a:  maximal stackuse in interruptable areas (in bytes) "
echo " Column 3b:  maximal stackuse in general (in bytes) "
echo " Column 3:   registeruse table (x=used, c=changed, .=unused) "
echo " Columd 4:   individual registers used, changed registers bracketed "
echo " "
echo " WARNING: This script assumes the assembly langauge has the jump vectors properly"
echo " named, thus, with a jump, something like <appLoop_LEDtask6>. However, sometimes the"
echo " disassembly states <RAM_end+0xc> or <__eeprom_end+0xff7ef7f8> instead of the real"
echo " targets. That maybe numerically correct, but cannot used for calculation. This"
echo " will result in not enough stackdepth of missed registers. "
echo " Furthermore, results are not yet correct for the 256 series, add one byte per call. "
echo " "
echo " "
echo " In the second table please find a list of the numbers generated by Femto OS for"
echo " the tasks, slots and files. Excluded files are not listed. These are the numbers"
echo " as used by the OS."
echo " "
echo " Column 1:  task, slot or file number"
echo " Column 2:  corresponding name"
echo " "
echo " "
echo " The last table gives an overview of the named variables and their location in"
echo " ram. Note that only global variables are listed, the names of other variables"
echo " are not exported to the main.map"
echo " "
echo " "
fi;

if [ -e $1 ] && ( [[ $4 == "" ]] || [[ $4 == "shell" ]] || [[ $4 == "registers" ]] )
then

# The first grep must filter all functions that cannot be reached from the application
# loop without changing the stack. This implies all switching calls as well as call that
# do not return. Other functions must be left in place. The second grep removes all functions
# that are of no interest to the user.
# Note: I am aware there is an recursion 'misuse' in the script below, but removal is difficult
# and it does no harm for the moment.


if [[ $4 != "shell" ]];
then echo "   Function ==========================  Stack ===   Regtable   Individual registers use (changed) ====";
else echo -e "\033[31m   Function ==========================  Stack ===   Regtable   Individual registers use (changed) ====\033[0m";
fi;

CPP="cpp"
if [ -e ./proc/bin/avr-cpp ]; then CPP="./proc/bin/avr-cpp"; fi;
if [ -e ../proc/bin/avr-cpp ]; then CPP="../proc/bin/avr-cpp"; fi;
if [ -e ../../proc/bin/avr-cpp ]; then CPP="../../proc/bin/avr-cpp"; fi;
if [ -e ../../../proc/bin/avr-cpp ]; then CPP="../../../proc/bin/avr-cpp"; fi;
if [ -e ../../../../proc/bin/avr-cpp ]; then CPP="../../../../proc/bin/avr-cpp"; fi;

awk ' \
{ for (i=1; i<=NF; i++) \
  { if (match($i,"<[a-z,A-Z,0-9,_]+>:"))        \
  { CurLabel=substr($i,RSTART+1,RLENGTH-3);
    print(""); printf("zzzzz %s %sMETHODE",$i,CurLabel);                \
    print(""); printf("%s ",$i);    } \
   else \
    { if (match($i,"<taskExitGlobalCritical>"))     { printf("exit ");  } \
      if (match($i,"<portExitGlobalInterrupts>"))   { printf("exit ");  } \
      if (match($i,"<taskExitTickCritical>"))       { printf("exit ");  } \
      if (match($i,"<portExitTickInterrupts>"))     { printf("exit ");  } \
      if (!match($i,CurLabel) && match($i,"<[a-z,A-Z,0-9,_]+>"))  { printf("push push %sMETHODE pop pop ",substr($i,RSTART+1,RLENGTH-2));  }  \
      if (match($i,"<taskEnterGlobalCritical>"))    { printf("enter "); } \
      if (match($i,"<portEnterGlobalInterrupts>"))  { printf("enter "); } \
      if (match($i,"<taskEnterTickCritical>"))      { printf("enter "); } \
      if (match($i,"<portEnterTickInterrupts>"))    { printf("enter "); } \
      if (length($i)<=4) \
      { if (match($i,"r[0-9]+,"))                { printf("%s ",substr($i,1,length($i)-1)) } \
        else if (match($i,"r[0-9]+"))            { printf("%s ",$i) }  \
        else if (match($i,"push"))               { printf("push ") }   \
        else if (match($i,"pop"))                { printf("pop ") } } } } } ' $1  | \
grep -v \
-e "<__.*>:" \
-e "<_exit>:" \
-e "<FemtoOSid>:" \
-e "<uiFileSpace>:" \
-e "<uiCapabilities>:" \
-e "<TaskNameStr..>:" \
-e "<tdb..>:" \
-e "<pxInitlist>:" \
-e "<pxBarklist>:" \
-e "<pxTCBlist>:" \
-e "<pxTDBlist>:" \
-e "<pxLooplist>:" \
-e "<pxQueulist>:" \
-e "<uiQueuSize>:" \
-e "<appBark_.*>:" \
-e "<appBoot>:" \
-e "<appInit_.*>:" \
-e "<appInitEnterIdle>:" \
-e "<appInitExitSleep>:" \
-e "<appTick..>:" \
-e "<genReboot>:" \
-e "<main>:" \
-e "<portReboot>:" \
-e "<portReturnISR>:" \
-e "<privDelayFromNowBody>:" \
-e "<privDelayFromWakeBody>:" \
-e "<privEnterIdle>:" \
-e "<privEnterOS>:" \
-e "<privEnterSleep>:" \
-e "<privEnterTask>:" \
-e "<privFileCloseBody>:" \
-e "<privFileOpenBody>:" \
-e "<privIsrExit>:" \
-e "<privTerminateBody>:" \
-e "<privRestartBody>:" \
-e "<privRecreateBody>:" \
-e "<privSleepBody>:" \
-e "<privSyncReleaseBody>:" \
-e "<privSyncRequestBody>:" \
-e "<privTickYield>:" \
-e "<privWaitForEventBody>:" \
-e "<privWaitForFsAccess>:" \
-e "<privWaitForFsAccessBody>:" \
-e "<privWaitForTasksBody>:" \
-e "<privYieldBody>:" \
-e "<SIG_OUTPUT_COMPARE0A>:" \
-e "<SIG_OUTPUT_COMPARE0>:" \
-e "<SIG_OVERFLOW0>:" \
-e "<SIG_WATCHDOG_TIMEOUT>:" \
-e "<SIG_WDT>:" \
-e "<taskDelayFromNow>:" \
-e "<taskDelayFromWake>:" \
-e "<taskFileClose>:" \
-e "<taskFileOpen>:" \
-e "<taskTerminate>:" \
-e "<taskRestart>:" \
-e "<taskRecreate>:" \
-e "<taskSleep>:" \
-e "<taskSleepAll>:" \
-e "<taskSuspend>:" \
-e "<taskSyncRelease>:" \
-e "<taskSyncRequest>:" \
-e "<taskWaitForEventSet>:" \
-e "<taskWaitForTasks>:" \
-e "<taskYield>:" |  \
awk ' \
{ if (match($1,"zzzzz"))
  { print(""); printf("%s_VARS ",substr($2,2,length($2)-3)); \
    for (i=3; i<=NF; i++) { printf("%s ",$i); } }
  else
  { for (i=1; i<=NF; i++) \
    { if (match($i,"<[a-z,A-Z,0-9,_]+>:")) { print(""); printf("#define %sMETHODE ",substr($i,RSTART+1,RLENGTH-3)) } \
     else printf("%s ",$i) } } } ' > temp_REGVARS
echo                                                          >> temp_REGVARS
echo "#define genRebootMETHODE "                              >> temp_REGVARS
echo "#define portRebootMETHODE "                             >> temp_REGVARS
echo "#define taskDelayFromNowMETHODE push push pop pop "     >> temp_REGVARS
echo "#define taskDelayFromWakeMETHODE push push pop pop "    >> temp_REGVARS
echo "#define taskFileCloseMETHODE push push pop pop "        >> temp_REGVARS
echo "#define taskFileOpenMETHODE push push pop pop "         >> temp_REGVARS
echo "#define taskTerminateMETHODE push push pop pop "        >> temp_REGVARS
echo "#define taskRestartMETHODE push push pop pop "          >> temp_REGVARS
echo "#define taskRecreateMETHODE push push pop pop "         >> temp_REGVARS
echo "#define taskSleepMETHODE push push pop pop "            >> temp_REGVARS
echo "#define taskSleepAllMETHODE push push pop pop "         >> temp_REGVARS
echo "#define taskSuspendMETHODE push push pop pop "          >> temp_REGVARS
echo "#define taskSyncReleaseMETHODE push push pop pop "      >> temp_REGVARS
echo "#define taskSyncRequestMETHODE push push pop pop "      >> temp_REGVARS
echo "#define taskWaitForEventSetMETHODE push push pop pop "  >> temp_REGVARS
echo "#define taskWaitForTasksMETHODE push push pop pop "     >> temp_REGVARS
echo "#define taskYieldMETHODE push push pop pop "            >> temp_REGVARS

#========================================================

cat temp_REGVARS | sort | $CPP | grep -v "#" |
awk ' \
{ vardecl=substr(substr($1,1,length($1)-5),1,32)
  printf("   %s: ",vardecl); \
  for (i=0; i<=34-length(vardecl); i++) { printf(" ") }
  for (i=0; i<32; i++) { used[i]=0; } \
  for (i=0; i<32; i++) { changed[i]=0; } \
  CritLev=0;
  StackUseLevel=0;
  StackUseMax=0;
  StackChangeLevel=0;
  StackChangeMax=0;
  for (i=2; i<=NF; i++) \
  { if (match($i,"enter")) { CritLev++; }
    if (match($i,"exit"))  { CritLev--; }
    if (match($i,"push"))
    { StackChangeLevel++;
      if (CritLev==0) { StackUseLevel++; }
      if (StackChangeMax<StackChangeLevel) { StackChangeMax=StackChangeLevel; }
      if (StackUseMax<StackUseLevel) { StackUseMax=StackUseLevel; } }
    if (match($i,"pop"))
    { StackChangeLevel--;
      if (CritLev==0) { StackUseLevel--; } }
    if (match($i,"r[0-9]+"))
    { Reg = substr($i,2,length($i)-1);
      changed[Reg]=1;
      if (CritLev==0) { used[Reg]=1; } } } \
  printf("%#3d (%#3d)   ",StackUseMax,StackChangeMax)
  for (i=28; i>=4; i=i-4) \
    { if ((used[3+i]==1) ||  (used[2+i]==1) || (used[1+i]==1) || (used[i]==1)) { printf("x") }
      else if ((changed[3+i]==1) ||  (changed[2+i]==1) || (changed[1+i]==1) || (changed[i]==1)) { printf("c") }
      else { printf(".") } } \
    { if ((used[3]==1) ||  (used[2]==1) || (used[0]==1)) { printf("x") }
      else if ((changed[3]==1) ||  (changed[2]==1) || (changed[0]==1)) { printf("c") }
      else { printf(".") } } \
  printf("   ")
  for (i=31; i>=0; i--) \
  { if (used[i]==1) { printf("r%s ",i); } else if (changed[i]==1) { printf("(r%s) ",i); } } \
  print(""); \
} ' |
grep -v \
-e "^   gen.*:" \
-e "^   isr.*:" \
-e "^   port.*:" \
-e "^   priv.*:" \
-e "^   task.*:"
rm temp_REGVARS

fi

if [ -e $2 ] && ( [[ $4 == "" ]] || [[ $4 == "shell" ]] || [[ $4 == "labels" ]] )
then

# This part of the script must be called with femtoos_shared.i to extract the
# Taks, slot and file numbers.

echo " "
if [[ $4 != "shell" ]];
then echo "   Label ====  Name ======================================== ";
else echo -e "\033[31m   Label ====  Name ======================================== \033[0m";
fi;

grep -e "defInfoCoupling.*_" $2 | grep -v -e "_[TLV]N_[0-1][0-9]" | \
\
awk '
{ for (i=1; i<=NF; i++)
  { if (match($i,"defInfoCoupling...._"))
    { Label = substr($i,RSTART+15,4)
      if (match($i,/_.*\[/))      { Name=substr($i,RSTART+1,RLENGTH-2); }
      if (match($i,/\[[0-9]*\]/)) { Num=substr($i,RSTART+1,RLENGTH-2); }
      if (length(Num)==1) { Label=Label" "; }
      printf("   %s %i     %s ",Label,Num,Name); print("");
      } } } '

# This part of the script must be called with main.map. It will extract the named
# variables.

fi

if [ -e $3 ] && ( [[ $4 == "" ]] || [[ $4 == "shell" ]] || [[ $4 == "fields" ]] )
then

echo " "
if [[ $4 != "shell" ]];
then echo "   Address     Fields ======================================";
else echo -e "\033[31m   Address     Fields ======================================\033[0m";
fi;

cat $3 | grep -e "0x00*80" | awk '
{ if (match($0,"__bss_end"))   { Active=0; }
  if (Active==1) { print($0); }
  if (match($0,"__bss_start")) { Active=1; }
}' |  grep -v -e "\./" | awk '
{ match($0,"0x00*80")
  Line=substr($0,RSTART+RLENGTH);
  split(Line,LA," ");
  printf("   0x%s      %s",LA[1],LA[2]); print("");
}' | sort

echo " "
if [[ $4 != "shell" ]];
then echo "   Address     Size =    Unit ==============================";
else echo -e "\033[31m   Address     Size =    Unit ==============================\033[0m";
fi;

cat $3 | grep -e "0x00*80" | awk '
{ if (match($0,"__bss_end"))   { Active=0; }
  if (Active==1) { print($0); }
  if (match($0,"__bss_start")) { Active=1; }
}' |  grep -e "\./" | awk '
{ match($0,"0x00*80")
  Line=substr($0,RSTART+RLENGTH);
  split(Line,LA," ");
  if (length(LA[2])==3) { SZE="0x000"substr(LA[2],3);}
  if (length(LA[2])==4) { SZE="0x00"substr(LA[2],3);}
  if (length(LA[2])==5) { SZE="0x0"substr(LA[2],3);}
  if (length(LA[2])==6) { SZE="0x"substr(LA[2],3); }
  printf("   0x%s      %s    %s",LA[1],SZE,LA[3]); print("");
}' | sort

fi